<?php
/**
 * JQuery Validation Plugin form decorator.
 *
 * Makes client-side validators from server side validators
 * with jQuery Validation Plugin.
 *
 * @todo Add all or more rules
 *
 * @category    IPB_CMS
 * @package     App_Form
 * @subpackage  Decorator
 * @copyright   Copyright (c) 2009 IPB CMS <http://ipb-cms.googlecode.com/>
 * @license     http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License
 * @author      Henrique Moody <henriquemoody@gmail.com>
 */
class App_Form_Decorator_JQueryValidation extends Zend_Form_Decorator_Abstract
{

    /**
     * Rules of jQuery Validation Plugin
     *
     * @var array
     */
    protected $_rules = array();

    /**
     * Render client-side form validators by server-side validators
     *
     * @param  string $content
     * @return string
     */
    public function render($content)
    {
        if ( ! $this->_element instanceof Zend_Form ) {
            return $content;
        }
        
        // Rules form elements
        $this->_setRules($this->_element);

        if (!empty($this->_rules)) {
            $view   = $this->_element->getView();
            $jquery = $view->jQuery();

            $jquery->enable();
            $jquery->addJavascriptFile(
                $view->baseUrl('js/jquery.validate/jquery.validate.min.js')
            );

            $lang = Zend_Locale::findLocale();
            $langFile = 'js/jquery.validate/lang/' . $lang . '.js';
            if (file_exists($langFile)) {
                $jquery->addJavascriptFile(
                    $view->baseUrl($langFile)
                );
            }

            $options = array();
            $options['rules'] = $this->_rules;
            $options['errorElement'] = 'div';

            $js = sprintf('%s("#%s").validate(%s);',
                ZendX_JQuery_View_Helper_JQuery::getJQueryHandler(),
                $this->_element->getId(),
                Zend_Json::encode($options)
            );
            $jquery->addOnLoad($js);
        }
        return $content;
    }

    /**
     * Sets the rules of jQuery Validation Plugin
     *
     * @param Zend_Form|Zend_Form_Element $element
     * @param Zend_Form $subForm
     */
    protected function _setRules($element, Zend_Form $subForm = null)
    {
        if ($element instanceof Zend_Form) {

            // Form elements
            foreach($element->getElements() as $formElement) {
                $this->_setRules($formElement, $element);
            }

            // Sub-forms
            foreach($element->getSubForms() as $subSubForm) {
                $this->_setRules($subSubForm);
            }

            // Stop method
            return;
        }

        if ( ! $element instanceof Zend_Form_Element ) {
            return;
        }

        $rules       = array();
        $validators  = $element->getValidators();

        if (null !== $subForm && $subForm->isArray()) {
            $elementName = $subForm->getName() . '[' . $element->getName() . ']';
        } else {
            $elementName = $element->getName();
        }

        if ($element->isRequired()) {
            $rules['required'] = true;
        }

        if (!empty($validators)) {
            foreach($validators as $validator) {
                if ($validator instanceof Zend_Validate_StringLength) {
                    if (is_array($validator->zfBreakChainOnFailure)) {
                        $rules['minlength'] = $validator->zfBreakChainOnFailure[0];
                        $rules['maxlength'] = $validator->zfBreakChainOnFailure[1];
                    } else {
                        $rules['maxlength'] = (int) $validator->zfBreakChainOnFailure;
                    }
                } else if ($validator instanceof Zend_Validate_EmailAddress) {
                    $rules['email'] = true;
                } else if ($validator instanceof Zend_Validate_Int) {
                    $rules['digits'] = true;
                }
            }
        }

        if (!empty($rules)) {
            $this->_rules[$elementName] = $rules;
        }
    }

}
